bitkeeper revision 1.996.1.1 (40d819aaW-H1hGnlbaPFjS7bKHhEaw)
authormjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Tue, 22 Jun 2004 11:36:10 +0000 (11:36 +0000)
committermjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Tue, 22 Jun 2004 11:36:10 +0000 (11:36 +0000)
Sundry small fixes, domain save/restore in xm.

tools/xend/lib/domain_controller.h
tools/xend/lib/utils.c
tools/xenmgr/lib/XendDomainInfo.py
tools/xenmgr/lib/server/channel.py
tools/xenmgr/lib/xm/create.py
tools/xenmgr/lib/xm/main.py

index af202b5ec349ca7e6f46bfad3331e964335f0bfc..8a9cea06640212f92f4213c605c3cca67431acc4 100644 (file)
@@ -523,21 +523,20 @@ typedef struct {
  */
 
 /*
- * Subtypes for console messages.
+ * Subtypes for suspend messages.
  */
 /* None. */
 
 
 /******************************************************************************
- * CONSOLE DEFINITIONS
+ * SHUTDOWN DEFINITIONS
  */
 
 /*
- * Subtypes for console messages.
+ * Subtypes for shutdown messages.
  */
 #define CMSG_SHUTDOWN_HALT      0   /* Shutdown and halt (don't die). */
 #define CMSG_SHUTDOWN_POWEROFF  1   /* 'Poweroff' => clean death.     */
 #define CMSG_SHUTDOWN_REBOOT    2   /* Shutdown and restart.          */
 
-
 #endif /* __DOMAIN_CONTROLLER_H__ */
index f761490648f89be371dc4fa8f9ae7c139fe5556d..2d96577203e8ad8ae21c8a73e983b8814b5eba33 100644 (file)
@@ -607,6 +607,7 @@ static PyObject *xu_message_new(PyObject *self, PyObject *args)
     case TYPE(CMSG_NETIF_FE, CMSG_NETIF_FE_DRIVER_STATUS_CHANGED):
         P2C(netif_fe_driver_status_changed_t, status,        u32);
         P2C(netif_fe_driver_status_changed_t, nr_interfaces, u32);
+        break;
     }
 
     if ( dict_items_parsed != PyDict_Size(payload) )
index f05397c1694d3a2de4ad0826f52ba815602b451c..db636136a2c78bab7506fd19f77c4ab9bbac1031 100644 (file)
@@ -350,6 +350,8 @@ def xen_domain_create(config, ostype, name, memory, kernel, ramdisk, cmdline, vi
     buildfn = getattr(xc, '%s_build' % ostype)
     
     print 'xen_domain_create> build ', ostype, dom, kernel, cmdline, ramdisk
+    if len(cmdline) >= 256:
+        print 'Warning: kernel cmdline too long'
     err = buildfn(dom            = dom,
                   image          = kernel,
                   control_evtchn = console.port2,
@@ -433,7 +435,6 @@ def vm_create(config):
     """
     # todo - add support for scheduling params?
     print 'vm_create>'
-    xenctl.vdisk.VBD_EXPERT_MODE = 0
     vm = None
     try:
         name = sxp.child_value(config, 'name')
index 04f7441f7ae68210db6e179c02a7a410f966be00..130d23254f35fb43b20abf79d83fbae36aec5a82 100755 (executable)
@@ -41,14 +41,28 @@ class ChannelFactory:
 
     def domChannel(self, dom):
         """Get the channel for the given domain.
+        Construct if necessary.
         """
         for chan in self.channels.values():
+            if not isinstance(chan, Channel): continue
             if chan.dom == dom:
                 return chan
         chan = Channel(self, dom)
         self.addChannel(chan)
         return chan
 
+    def virqChannel(self, virq):
+        """Get the channel for the given virq.
+        Construct if necessary.
+        """
+        for chan in self.channels.values():
+            if not isinstance(chan, VirqChannel): continue
+            if chan.virq == virq:
+                return chan
+        chan = VirqChannel(self, virq)
+        self.addChannel(chan)
+        return chan
+
     def channelClosed(self, channel):
         """The given channel has been closed - remove it.
         """
@@ -70,28 +84,127 @@ def channelFactory():
         inst = ChannelFactory()
     return inst
 
-class Channel:
+class BaseChannel:
+    """Abstract superclass for channels.
+
+    The subclass constructor must set idx to the port to use.
+    """
+
+    def __init__(self, factory):
+        self.factory = factory
+        self.idx = -1
+        self.closed = 0
+
+    def getIndex(self):
+        """Get the channel index.
+        """
+        return self.idx
+
+    def notificationReceived(self, type):
+        """Called when a notification is received.
+        Closes the channel on error, otherwise calls
+        handleNotification(type), which should be defined
+        in a subclass.
+        """
+        #print 'notificationReceived> type=', type, self
+        if self.closed: return
+        if type == self.factory.notifier.EXCEPTION:
+            print 'notificationReceived> EXCEPTION'
+            info = xc.evtchn_status(self.idx)
+            if info['status'] == 'unbound':
+                print 'notificationReceived> EXCEPTION closing...'
+                self.close()
+                return
+        self.handleNotification(type)
+
+    def close(self):
+        """Close the channel. Calls channelClosed() on the factory.
+        Override in subclass.
+        """
+        self.factory.channelClosed(self)
+
+    def handleNotification(self, type):
+        """Handle notification.
+        Define in subclass.
+        """
+        pass
+        
+
+class VirqChannel(BaseChannel):
+    """A channel for handling a virq.
+    """
+    
+    def __init__(self, factory, virq):
+        """Create a channel for the given virq using the given factory.
+
+        Do not call directly, use virqChannel on the factory.
+        """
+        BaseChannel.__init__(self, factory)
+        self.virq = virq
+        # Notification port (int).
+        self.port = xc.evtchn_bind_virq(virq)
+        self.idx = port
+        # Clients to call when a virq arrives.
+        self.clients = []
+
+    def __repr__(self):
+        return ('<VirqChannel virq=%d port=%d>'
+                % (self.virq, self.port))
+
+    def getVirq(self):
+        """Get the channel's virq.
+        """
+        return self.virq
+
+    def close(self):
+        """Close the channel. Calls lostChannel(self) on all its clients and
+        channelClosed() on the factory.
+        """
+        for c in self.clients:
+            c.lostChannel(self)
+        del self.clients
+        BaseChannel.close(self)
+
+    def registerClient(self, client):
+        """Register a client. The client will be called with
+        client.virqReceived(virq) when a virq is received.
+        The client will be called with client.lostChannel(self) if the
+        channel is closed.
+        """
+        self.clients.append(client)
+
+    def handleNotification(self, type):
+        for c in self.clients:
+            c.virqReceived(self.virq)
+
+    def notify(self):
+        xc.evtchn_send(self.port)
+
+
+class Channel(BaseChannel):
     """A control channel to a domain. Messages for the domain device controllers
     are multiplexed over the channel (console, block devs, net devs).
     """
 
     def __init__(self, factory, dom):
         """Create a channel to the given domain using the given factory.
+
+        Do not call directly, use domChannel on the factory.
         """
-        self.factory = factory
+        BaseChannel.__init__(self, factory)
+        # Domain.
         self.dom = dom
+        # Domain port (object).
         self.port = self.factory.createPort(dom)
+        # Channel port (int).
         self.idx = self.port.local_port
+        # Registered devices.
         self.devs = []
+        # Devices indexed by the message types they handle.
         self.devs_by_type = {}
-        self.closed = 0
+        # Output queue.
         self.queue = []
 
-    def getIndex(self):
-        """Get the channel index.
-        """
-        return self.idx
-
     def getLocalPort(self):
         """Get the local port.
         """
@@ -153,23 +266,13 @@ class Channel:
                    self.port.local_port,
                    self.port.remote_port))
 
-    def notificationReceived(self, type):
-        #print 'notificationReceived> type=', type, self
-        if self.closed: return
-        if type == self.factory.notifier.EXCEPTION:
-            print 'notificationReceived> EXCEPTION'
-            info = xc.evtchn_status(self.idx)
-            if info['status'] == 'unbound':
-                print 'notificationReceived> EXCEPTION closing...'
-                self.close()
-                return
+    def handleNotification(self, type):
         work = 0
         work += self.handleRequests()
         work += self.handleResponses()
         work += self.handleWrites()
         if work:
             self.notify()
-        #print 'notificationReceived<', work
 
     def notify(self):
         self.port.notify()
index 3843007a10748f327aac67e2430e1064da6c411d..a5e9e888c54171489337b8f37aea55c7fc51ee22 100644 (file)
@@ -30,7 +30,11 @@ gopts.opt('defaults', short='f', val='FILE',
 
 gopts.opt('config', short='F', val='FILE',
          fn=set_value, default=None,
-         use='Domain configuration to use.')
+         use='Domain configuration to use (SXP).')
+
+gopts.opt('load', short='L', val='FILE',
+          fn=set_value, default=None,
+          use='Domain saved state to load.')
 
 def set_var(opt, k, v):
     opt.set(v)
@@ -231,6 +235,7 @@ def preprocess_ip(opts):
     setip = (opts.hostname or opts.netmask
              or opts.gateway or opts.dhcp or opts.interface)
     if not setip: return
+    if not opts
     ip = (opts.ip
           + ':'
           + ':' + opts.gateway
@@ -261,10 +266,9 @@ def make_domain(opts, config):
     """Create, build and start a domain.
     Returns: [int] the ID of the new domain.
     """
-    restore = 0 #todo
-
-    if restore:
-        dominfo = server.xend_domain_restore(state_file, config)
+    if opts.load:
+        filename = os.path.abspath(opts.load)
+        dominfo = server.xend_domain_restore(filename, config)
     else:
         dominfo = server.xend_domain_create(config)
 
@@ -285,13 +289,13 @@ def make_domain(opts, config):
 def main(argv):
     opts = gopts
     args = opts.parse(argv)
+    if opts.help:
+        opts.usage()
+        return
     if opts.config:
         pass
     else:
         opts.load_defaults()
-    if opts.help:
-        opts.usage()
-        return
     preprocess(opts)
     config = make_config(opts)
     if opts.dryrun:
index 32a7be879b58731b47130f4410c170e5e861f244..fb7d839f4ac4bdbded28f3bab4215b2f54fc765a 100644 (file)
@@ -1,4 +1,8 @@
-#!/usr/bin/python
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Grand unified management application for Xen.
+"""
+import os
+import os.path
 import sys
 
 from xenmgr import PrettyPrint
@@ -17,6 +21,8 @@ class Xm:
         sys.exit(1)
 
     def main(self, args):
+        """Main entry point. Dispatches to the xm_ methods.
+        """
         self.prog = args[0]
         if len(args) < 2:
             self.err("Missing command\nTry '%s help' for more information."
@@ -33,10 +39,16 @@ class Xm:
         return 0
 
     def unknown(self, help, args):
-        self.err("Unknown command: %s\nTry '%s help' for more information."
-                 % (args[0], self.prog))
+        if help and len(args) == 1:
+            self.xm_help(help, args)
+        else:
+            self.err("Unknown command: %s\nTry '%s help' for more information."
+                     % (args[0], self.prog))
 
     def help(self, meth, args):
+        """Print help on an xm_ method.
+        Uses the method documentation string if there is one.
+        """
         name = meth[3:]
         f = getattr(self, meth)
         print "%-14s %s" % (name, f.__doc__ or '')
@@ -53,24 +65,36 @@ class Xm:
         create.main(args)
 
     def xm_save(self, help, args):
-        """Save domain state to file."""
+        """Save domain state (and config) to file."""
         if help:
-            print args[0], "DOM FILE"
-            print "\nSave domain with id DOM to FILE."
+            print args[0], "DOM FILE [CONFIG]"
+            print """\nSave domain with id DOM to FILE.
+            Optionally save config to CONFIG."""
             return
         if len(args) < 3: self.err("%s: Missing arguments" % args[0])
         dom = args[1]
-        filename = args[2]
-        server.xend_domain_save(dom, filename)
-
+        savefile = os.path.abspath(args[2])
+        configfile = None
+        if len(args) == 4:
+            configfile = os.path.abspath(args[3])
+        if configfile:
+            out = file(configfile, 'w')
+            config = server.xend_domain(dom)
+            PrettyPrint.prettyprint(config, out=out)
+            out.close()
+        server.xend_domain_save(dom, savefile)
+            
     def xm_restore(self, help, args):
         """Create a domain from a saved state."""
         if help:
-            print args[0], "FILE"
-            print "\nRestore a domain from FILE."
-        if len(args) < 2: self.err("%s: Missing file" % args[0])
-        filename = args[1]
-        server.xend_domain_restore(None, filename)
+            print args[0], "FILE CONFIG"
+            print "\nRestore a domain from FILE using configuration CONFIG."
+            return
+        if len(args) < 3: self.err("%s: Missing arguments" % args[0])
+        savefile =  os.path.abspath(args[1])
+        configfile = os.path.abspath(args[2])
+        info = server.xend_domain_restore(savefile, configfile)
+        PrettyPrint.prettyprint(info)
 
     def xm_domains(self, help, args):
         """List domains."""